#include <sys/types.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <cutils/properties.h>
#include "myjni.h"
#include "platform_config.h"

u8 g_flagOfBatteryPull = 0;

#define IP_ADDR "192.168.43.1"
#define PORT 54321
#define BUFFER_MAX    1024  /* input buffer for commands */
#define TOKEN_MAX     32     /* max number of arguments in buffer */
#define REPLY_MAX     1024   /* largest reply allowed */
//#undef LOGE
//#undef ALOGE
//#define LOGE(arg...)
//#define ALOGE(arg...)
extern SysInf  SysInfor;
extern int priv_fd;
extern char iccid[PROPERTY_VALUE_MAX];
extern volatile int gps_state;
static int running  = 0;
extern int ultra_depth;
struct cmdinfo {
    const char *name;
    unsigned numargs;
    int (*func)(char **arg, char reply[REPLY_MAX]);
};

static int getCurrentAngleAndDepth(char** arg, char reply[REPLY_MAX])
{
	SysInf* p = &SysInfor;
	sprintf(reply, "replayAngleAndDepth %f %d %f %d %d %d", g_currentAngle * 100, ultra_depth, g_currentAngle_b * 100, p->sensor_model, p->plough_model, plough_state);
	return 0;
}

static int readParameter(char **arg, char reply[REPLY_MAX])
{
    SysInf *p = &SysInfor;
    
    memset(reply, 0, REPLY_MAX);
    snprintf(reply, REPLY_MAX, "replyParameter %s %hd %s %s %s %f %d %d %d %d %d %d %d %d %s end", p->IP, p->port, p->terminalID, p->CarNumber_utf8, iccid, p->machine_width, p->depth, p->ref_depth, p->angle, p->a_sensor_height, p->sensor_model, p->angle_b, p->a_sensor_height_b, p->plough_model, p->plough_care_id);

    return 0;
}

static int setParameter(char **arg, char reply[REPLY_MAX])
{
    int i = 0;
    SysInf sysinfo = SysInfor;
    SysInf *p = &sysinfo;

    if (strcmp(arg[9], "end"))
            goto out;

    while (arg[i]) {
        LOGE("arg[%d]=%s", i, arg[i]);
        i++;
    }
    if (strcmp(p->IP, arg[0]) || (p->port != atoi(arg[1]))) {
        flag_login = 0;
        flag_newIp = 1;
    }
    strcpy(p->IP, arg[0]);
    p->port = atoi(arg[1]);
    strcpy(p->terminalID, arg[2]);
    strcpy(p->CarNumber_utf8, arg[3]);
    sprintf((char*)p->LocalPhoneNum1,"01861%s", (char*)p->terminalID);
	p->machine_width = atoi(arg[4]);
	p->depth = atoi(arg[5]);
	p->ref_depth = atoi(arg[6]);
	p->plough_model = atoi(arg[7]);
	strcpy(p->plough_care_id, arg[8]);

    int unicode;
    char *p_int = (char *)&unicode;
    int u_len = UTF8toUnicode((unsigned char *)arg[3], &unicode);
    sprintf(p->CarNumber + 2, "%s", arg[3] + u_len);
    p->CarNumber[sizeof(p->CarNumber) - 1] = 0; //防止参数过长溢出
    p->CarNumber[0] = p_int[1];
    p->CarNumber[1] = p_int[0];

    if (memcmp((void *)p, (void *)&SysInfor, sizeof(SysInf))) {
        SysInfor = sysinfo;
        BlockWrite((char *)&SysInfor, SysInfLength, SYSINFO_SET);
    }
    strcpy(reply, "okay");
    reply[4] = 0;

    return 0;

out:
    strcpy(reply, "error");
    reply[5] = 0;

    return 0;
}

static int setAngleParameter(char **arg, char reply[REPLY_MAX])
{
    int i = 0;
    SysInf sysinfo = SysInfor;
    SysInf *p = &sysinfo;

    if (strcmp(arg[5], "end"))
            goto out;

    while (arg[i]) {
        LOGE("arg[%d]=%s", i, arg[i]);
        i++;
    }
	p->sensor_model = atoi(arg[2]);
	if (p->sensor_model == 1 || p->sensor_model == 3)
	{
		p->angle = atoi(arg[0]);
		p->a_sensor_height = atoi(arg[1]);
	}
	if (p->sensor_model == 2 || p->sensor_model == 3)
	{
		p->angle_b = atoi(arg[3]);
		p->a_sensor_height_b = atoi(arg[4]);
	}

    if (memcmp((void *)p, (void *)&SysInfor, sizeof(SysInf))) {
        SysInfor = sysinfo;
        BlockWrite((char *)&SysInfor, SysInfLength, SYSINFO_SET);
    }
    strcpy(reply, "okay");
    reply[4] = 0;

    return 0;

out:
    strcpy(reply, "error");
    reply[5] = 0;

    return 0;
}

static int autoAngle(char** arg, char reply[REPLY_MAX])
{
	int i = 0;
	SysInf sysinfo = SysInfor;
	SysInf* p = &sysinfo;

	int angle = (int)(g_currentAngle * 100);
	p->angle = angle;

	if (memcmp((void*)p, (void*)& SysInfor, sizeof(SysInf))) {
		SysInfor = sysinfo;
		BlockWrite((char*)& SysInfor, SysInfLength, SYSINFO_SET);
	}
	strcpy(reply, "okay");
	reply[4] = 0;

	return 0;

out:
	strcpy(reply, "error");
	reply[5] = 0;

	return 0;
}

static int autoAngleB(char** arg, char reply[REPLY_MAX])
{
	int i = 0;
	SysInf sysinfo = SysInfor;
	SysInf* p = &sysinfo;

	int angle = (int)(g_currentAngle_b * 100);
	p->angle_b = angle;

	if (memcmp((void*)p, (void*)&SysInfor, sizeof(SysInf))) {
		SysInfor = sysinfo;
		BlockWrite((char*)&SysInfor, SysInfLength, SYSINFO_SET);
	}
	strcpy(reply, "okay");
	reply[4] = 0;

	return 0;

out:
	strcpy(reply, "error");
	reply[5] = 0;

	return 0;
}

static int autoDepthAdjust(char **arg, char reply[REPLY_MAX])
{
    int i = 0;
    SysInf sysinfo = SysInfor;
    SysInf *p = &sysinfo;

	if (strcmp(arg[1], "end"))
		goto out;

	while (arg[i]) {
		LOGE("arg[%d]=%s", i, arg[i]);
		i++;
	}
	double depth = atof(arg[0]);
	double modulus = depth / (double)ultra_depth;
	double sensorHeight = (double)SysInfor.a_sensor_height * modulus;
	if (sensorHeight <2000 && sensorHeight > -2000)
	{
		p->a_sensor_height = sensorHeight;
	}
	else
	{
		goto out;
	}

    if (memcmp((void *)p, (void *)&SysInfor, sizeof(SysInf))) {
        SysInfor = sysinfo;
        BlockWrite((char *)&SysInfor, SysInfLength, SYSINFO_SET);
    }
    strcpy(reply, "okay");
    reply[4] = 0;

    return 0;

out:
    strcpy(reply, "error");
    reply[5] = 0;

    return 0;
}

static int autoDepthAdjustB(char** arg, char reply[REPLY_MAX])
{
	int i = 0;
	SysInf sysinfo = SysInfor;
	SysInf* p = &sysinfo;

	if (strcmp(arg[1], "end"))
		goto out;

	while (arg[i]) {
		LOGE("arg[%d]=%s", i, arg[i]);
		i++;
	}
	double depth = atof(arg[0]);
	double modulus = depth / (double)ultra_depth;
	double sensorHeight = (double)SysInfor.a_sensor_height_b * modulus;
	if (sensorHeight <2000 && sensorHeight > -2000)
	{
		p->a_sensor_height_b = sensorHeight;
	}
	else
	{
		goto out;
	}

	if (memcmp((void*)p, (void*)&SysInfor, sizeof(SysInf))) {
		SysInfor = sysinfo;
		BlockWrite((char*)&SysInfor, SysInfLength, SYSINFO_SET);
	}
	strcpy(reply, "okay");
	reply[4] = 0;

	return 0;

out:
	strcpy(reply, "error");
	reply[5] = 0;

	return 0;
}

static int reinitParameter(char **arg, char reply[REPLY_MAX])
{
    reinitSysPara();
    strcpy(reply, "okay");
    reply[5] = 0;
    return 0;
}

void *restart_thread(void * arg) {
    sleep(1);
    system("reboot");
    return NULL;
}

static int restart(char **arg, char reply[REPLY_MAX])
{
    if (strcmp(arg[0], "3699"))//restart device need a password
        goto out;
    pthread_t thread;
    pthread_create(&thread, NULL, restart_thread, NULL);
    strcpy(reply, "okay");
    reply[5] = 0;
    return 0;
out:
    strcpy(reply, "error");
    reply[5] = 0;

    return 0;
}

static int workStatus(char **arg, char reply[REPLY_MAX])
{
    sprintf(reply, "replyWorkStatus %d %d", gps_state, flag_login);
    reply[5] = 0;
    return 0;
}

static int heartbeat(char **arg, char reply[REPLY_MAX])
{
    sprintf(reply, "heartbeat");
    reply[9] = 0;
    return 0;
}

struct cmdinfo cmds[] = {
	{ "getCurrentAngleAndDepth",                   0,  getCurrentAngleAndDepth },
    { "readParameter",             0,  readParameter },
    { "setParameter",              10,  setParameter },
	{ "autoAngle",              0,  autoAngle },
	{ "autoDepthAdjust",              2,  autoDepthAdjust },
	{ "autoAngleB",              0,  autoAngleB },
	{ "autoDepthAdjustB",              2,  autoDepthAdjustB },
	{ "setAngleParameter",              6,  setAngleParameter },
    { "reinitParameter",           0,  reinitParameter },
    { "restart",                   1,  restart },
    { "workStatus",                0,  workStatus },
    { "heartbeat",                0,  heartbeat },
};

static int readx(int s, void *_buf, int count)
{
    char *buf = _buf;
    int n = 0, r;
    if (count < 0) return -1; 
    while (n < count) {
        r = read(s, buf + n, count - n); 
        if (r < 0) {
            if (errno == EINTR) continue;
            ALOGE("read error: %s\n", strerror(errno));
            return -1; 
        }
        if (r == 0) {
            ALOGE("eof\n");
            return -1; /* EOF */
        }
        n += r;
    }   
    return 0;
}

static int writex(int s, const void *_buf, int count)
{
    const char *buf = _buf;
    int n = 0, r;
    if (count < 0) return -1; 
    while (n < count) {
        r = write(s, buf + n, count - n); 
        if (r < 0) {
            if (errno == EINTR) continue;
            ALOGE("write error: %s\n", strerror(errno));
            return -1; 
        }
        n += r;
    }   
    return 0;
}


/* Tokenize the command buffer, locate a matching command,
 * ensure that the required number of arguments are provided,
 * call the function(), return the result.
 */
static int execute(int s, char cmd[BUFFER_MAX])
{
    char reply[REPLY_MAX];
    char *arg[TOKEN_MAX+1];
    unsigned i;
    unsigned n = 0;
    unsigned short count;
    int ret = -1;

    //ALOGE("execute('%s')\n", cmd);

        /* default reply is "" */
    reply[0] = 0;

        /* n is number of args (not counting arg[0]) */
    arg[0] = cmd;
    while (*cmd) {
        if (isspace(*cmd)) {
            *cmd++ = 0;
            n++;
            arg[n] = cmd;
            if (n == TOKEN_MAX) {
                ALOGE("too many arguments\n");
                goto done;
            }
        }
        cmd++;
    }

    for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
        if (!strcmp(cmds[i].name,arg[0])) {
            if (n != cmds[i].numargs) {
                ALOGE("%s requires %d arguments (%d given)\n",
                     cmds[i].name, cmds[i].numargs, n);
            } else {
                ret = cmds[i].func(arg + 1, reply);
            }
            goto done;
        }
    }
    ALOGE("unsupported command '%s'\n", arg[0]);

done:
    if (reply[0]) {
        n = snprintf(cmd, BUFFER_MAX, "%s", reply);
    } else {
        n = snprintf(cmd, BUFFER_MAX, "%d", ret);
    }
    if (n > BUFFER_MAX) n = BUFFER_MAX;
    count = n;

    // ALOGI("reply: '%s'\n", cmd);
    if (writex(s, &count, sizeof(count))) return -1;
    if (writex(s, cmd, count)) return -1;
    return 0;
}


#if 1
void *translate_data(void * arg) {
    int bytes;
    char buf[BUFFER_MAX];
    int s = (int)arg;

    while (running) {
        fd_set fds;
        struct timeval tv; 
        int r;
        FD_ZERO (&fds);
        FD_SET (s, &fds);
        tv.tv_sec = 7; 
        tv.tv_usec = 0;

        //LOGE("%s select", __func__);
        r = select(s+1, &fds, NULL, NULL, &tv);
        //LOGE("%s select out, r=%d, errno[%d]=%s", __func__, r, errno, strerror(errno));
        if (-1 == r) {
            if (EINTR == errno)
                continue;
            LOGE("%s select", __func__);
        }
        if (0 == r) {
            LOGE( "select timeout\n");
            break; 
        }
        if (FD_ISSET(s, &fds)) {
            unsigned short count;
            if (readx(s, &count, sizeof(count))) {
                ALOGE("failed to read size\n");
                break;
            }
            if ((count < 1) || (count >= BUFFER_MAX)) {
                ALOGE("invalid size %d\n", count);
                break;
            }
            if (readx(s, buf, count)) {
                ALOGE("failed to read command\n");
                break;
            }
            buf[count] = 0;
            //LOGE("%s buf=%s", __func__, buf);
            if (execute(s, buf)) break;
        }
    }  
out:
    LOGE("%s thread exit", __func__);
    close(s);
    return NULL;
}
#endif

static int power_detect_fd = -1;
static int power_detect_gpio_value = -1;
static long power_detect_interval = 0;
extern u32 g_stopSeconds;
extern u32 planePointIndex;
extern u16 g_stopIndex;


int extract_update_package(char *path) {
    char cmd[64];

    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "unzip:%s", path);
    property_set("rw.exract.update.package", cmd);

    return 0;
}

volatile int power_irq_state = POWER_INIT;
static void power_detect_irq(int signum) {
    int ret, value;
    ret = read(power_detect_fd, &value, sizeof(value));
    if (ret == sizeof(value)) {
        LOGE("%s value=%d", __func__, value);
        if (value & (~3)) {
            power_irq_state = POWER_OFF;
        } else {
            power_irq_state = POWER_ON;
        }
    }
}


int power_detect_signal(void) {
    power_detect_fd = open(POWER_DETECT_PATH, O_RDWR);
    if (power_detect_fd < 0) {
        printf("open %s fail err=%s\n", POWER_DETECT_PATH, strerror(errno));
        return -1; 
    }   

    signal(SIGIO, power_detect_irq);
    fcntl(power_detect_fd, F_SETOWN, getpid());
    fcntl(power_detect_fd, F_SETFL, fcntl(power_detect_fd, F_GETFL) | FASYNC);

    return power_detect_fd;
}




void *listenWifiAp(void * arg)
{
    int fd, s, struct_len;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    char buf[BUFFER_MAX];
    void *result;

    if (running)
        return NULL;
    running = 1;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    //inet_pton(AF_INET, IP_ADDR, &server_addr.sin_addr);
    bzero(&(server_addr.sin_zero), 8);
    struct_len = sizeof(struct sockaddr_in);

    fd = socket(AF_INET, SOCK_STREAM, 0);
    while(bind(fd, (struct sockaddr *)&server_addr, struct_len) == -1) {
        LOGE("%s fail to bind err=%s\n", __func__, strerror(errno));
        sleep(5);
    };
    LOGE("%s Bind Success!\n", __func__);
    while(listen(fd, 5) == -1) {
        LOGE("%s fail to listen err=%s\n", __func__, strerror(errno));
        sleep(5);
    };
    while (running) {
        LOGE("%s Listening....\n", __func__);
        s = accept(fd, (struct sockaddr *)&client_addr, &struct_len);
        if (s < 0) {
            LOGE("%s accept err=%s", __func__, strerror(errno));
            break;
        }
        LOGE("%s Get the Client.\n", __func__);
        pthread_t thread;
        pthread_create(&thread, NULL, translate_data, (void *)s);
        pthread_join(thread, &result);
        ALOGE("%s close fd", __func__);
    }
    close(fd);
    return NULL;
}
